package plp;

import java.applet.Applet;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import plp.expressions1.parser.Exp1Parser;
import plp.expressions1.parser.ParseException;
import plp.expressions2.expression.ValorBooleano;
import plp.expressions2.expression.ValorInteiro;
import plp.expressions2.expression.ValorString;
import plp.expressions2.parser.Exp2Parser;
import plp.functional1.parser.Func1Parser;
import plp.functional2.parser.Func2Parser;
import plp.imperative1.memory.ContextoCompilacaoImperativa;
import plp.imperative1.memory.ContextoExecucaoImperativa;
import plp.imperative1.memory.ListaValor;
import plp.imperative1.parser.Imp1Parser;
import plp.imperative2.memory.ContextoCompilacaoImperativa2;
import plp.imperative2.memory.ContextoExecucaoImperativa2;
import plp.imperative2.parser.Imp2Parser;
import plp.orientadaObjetos1.parser.OO1Parser;

public class AppletInterpretadorPLP extends Applet {

    private AppletInterpretadorKeyListener listener;
    
    private JPanel jContentPane = null;
    private JTextArea jTextAreaCodigo = null;
    private JScrollPane jScrollPaneMensagens = null;
    private JTextArea jTextAreaMensagens = null;
    private JLabel jLabelCodigo = null;
    private JLabel jLabelMasg = null;
    private JScrollPane jScrollPaneCodigo = null;
    private JComboBox jComboBoxLinguagens = null;
    private JLabel jLabelExecutar = null;

    private Exp1Parser exp1Parser = null;
    private Exp2Parser exp2Parser = null;
    private Func1Parser func1Parser = null;
    private Func2Parser func2Parser = null;
    private Imp1Parser imp1Parser = null;
    private Imp2Parser imp2Parser = null;
    private OO1Parser oo1Parser = null;

    private JButton jButtonExecutar = null;
    private JTextField jTextFieldListaEntrada = null;
    private JLabel jLabelListaEntrada = null;

    /**
     * This is the default constructor
     */
    public AppletInterpretadorPLP() {
        super();
        initialize();
    }

    /**
     * This method initializes this
     * 
     * @return void
     */
    private void initialize() {
        getJContentPane();
        this.setBounds(new java.awt.Rectangle(300, 200, 389, 429));
        this.listener = new AppletInterpretadorKeyListener(this);
        this.jTextAreaCodigo.addKeyListener(this.listener);
        this.jTextAreaMensagens.addKeyListener(this.listener);
        this.jTextFieldListaEntrada.addKeyListener(this.listener);
        this.jTextFieldListaEntrada.setEnabled(false);

    }

    /**
     * This method initializes jContentPane
     * 
     * @return javax.swing.JPanel
     */
    private Panel getJContentPane() {
        if (jContentPane == null) {
            jLabelListaEntrada = new JLabel();
            jLabelListaEntrada.setBounds(new java.awt.Rectangle(20, 194, 127,
                    20));
            jLabelListaEntrada
                    .setToolTipText("informe os valores da lista de entrada separados por espa�os");
            jLabelListaEntrada.setText("Lista de Entrada");
            jLabelExecutar = new JLabel();
            jLabelExecutar.setBounds(new java.awt.Rectangle(19, 434, 157, 17));
            jLabelExecutar.setText("Pressione F1 para executar");
            jLabelMasg = new JLabel();
            jLabelMasg.setBounds(new java.awt.Rectangle(20, 245, 80, 16));
            jLabelMasg.setText("Mensagens");
            jLabelCodigo = new JLabel();
            jLabelCodigo.setBounds(new java.awt.Rectangle(20, 33, 70, 16));
            jLabelCodigo.setText("C�digo");
            jContentPane = new JPanel();
            jContentPane.setLayout(null);
            this.setLayout(null);
            this.add(getJScrollPaneMensagens(), null);
            this.add(jLabelCodigo, null);
            this.add(jLabelMasg, null);
            this.add(getJScrollPaneCodigo(), null);
            this.add(getJTextFieldListaEntrada(), null);
            this.add(getJComboBoxLinguagens(), null);
            this.add(jLabelExecutar, null);
            this.add(getJButton(), null);
            this.add(jLabelListaEntrada, null);
        }
        return this;
    }

    /**
     * This method initializes jTextAreaCodigo
     * 
     * @return javax.swing.JTextArea
     */
    private JTextArea getJTextAreaCodigo() {
        if (jTextAreaCodigo == null) {
            jTextAreaCodigo = new JTextArea();
        }
        return jTextAreaCodigo;
    }

    /**
     * This method initializes jScrollPaneMensagens
     * 
     * @return javax.swing.JScrollPane
     */
    private JScrollPane getJScrollPaneMensagens() {
        if (jScrollPaneMensagens == null) {
            jScrollPaneMensagens = new JScrollPane();
            jScrollPaneMensagens.setBounds(new java.awt.Rectangle(20, 267, 350,
                    160));
            jScrollPaneMensagens.setViewportView(getJTextAreaMensagens());
        }
        return jScrollPaneMensagens;
    }

    /**
     * This method initializes jTextAreaMensagens
     * 
     * @return javax.swing.JTextArea
     */
    private JTextArea getJTextAreaMensagens() {
        if (jTextAreaMensagens == null) {
            jTextAreaMensagens = new JTextArea();
        }
        return jTextAreaMensagens;
    }

    /**
     * This method initializes jScrollPane
     * 
     * @return javax.swing.JScrollPane
     */
    private JScrollPane getJScrollPaneCodigo() {
        if (jScrollPaneCodigo == null) {
            jScrollPaneCodigo = new JScrollPane();
            jScrollPaneCodigo
                    .setBounds(new java.awt.Rectangle(20, 52, 350, 134));
            jScrollPaneCodigo.setViewportView(getJTextAreaCodigo());
        }
        return jScrollPaneCodigo;
    }

    /**
     * This method initializes jComboBoxLingaugens
     * 
     * @return javax.swing.JComboBox
     */
    private JComboBox getJComboBoxLinguagens() {
        if (jComboBoxLinguagens == null) {
            jComboBoxLinguagens = new JComboBox();
            jComboBoxLinguagens
                    .setBounds(new java.awt.Rectangle(19, 7, 250, 20));
            jComboBoxLinguagens
                    .addActionListener(new java.awt.event.ActionListener() {
                        public void actionPerformed(java.awt.event.ActionEvent e) {
                            switch (jComboBoxLinguagens.getSelectedIndex()) {
                                case 0:
                                case 1:
                                case 2:
                                case 3:
                                    jTextFieldListaEntrada.setEnabled(false);
                                    break;
                                default:
                                    jTextFieldListaEntrada.setEnabled(true);
                                    break;
                            }
                        }
                    });
            jComboBoxLinguagens.addItem("Expressoes 1");
            jComboBoxLinguagens.addItem("Expressoes 2");
            jComboBoxLinguagens.addItem("Funcional 1");
            jComboBoxLinguagens.addItem("Funcional 2");
            jComboBoxLinguagens.addItem("Imperativa 1");
            jComboBoxLinguagens.addItem("Imperativa 2");
            jComboBoxLinguagens.addItem("Orientada a Objetos 1");

        }
        return jComboBoxLinguagens;
    }

    /**
     * This method initializes jButton
     * 
     * @return javax.swing.JButton
     */
    private JButton getJButton() {
        if (jButtonExecutar == null) {
            jButtonExecutar = new JButton();
            jButtonExecutar.setBounds(new java.awt.Rectangle(283, 8, 86, 19));
            jButtonExecutar.setText("executar");
            jButtonExecutar
                    .addActionListener(new java.awt.event.ActionListener() {
                        public void actionPerformed(java.awt.event.ActionEvent e) {
                            interpretarCodigo();
                        }
                    });
        }
        return jButtonExecutar;
    }

    /**
     * This method initializes jTextFieldListaEntrada
     * 
     * @return javax.swing.JTextField
     */
    private JTextField getJTextFieldListaEntrada() {
        if (jTextFieldListaEntrada == null) {
            jTextFieldListaEntrada = new JTextField();
            jTextFieldListaEntrada.setBounds(new java.awt.Rectangle(20, 218,
                    350, 20));
            jTextFieldListaEntrada
                    .setToolTipText("informe os valores da lista de entrada separados por espa�os");
        }
        return jTextFieldListaEntrada;
    }

    public static void main(String[] args) {
        (new InterpretadorPLP()).setVisible(true);
    }

    public void interpretarCodigo() {
        try {
            ByteArrayInputStream fis = new ByteArrayInputStream(jTextAreaCodigo
                    .getText().getBytes());

            switch (this.jComboBoxLinguagens.getSelectedIndex()) {
                case 0:
                    interpretarExp1(fis);
                    break;
                case 1:
                    interpretarExp2(fis);
                    break;
                case 2:
                    interpretarFunc1(fis);
                    break;
                case 3:
                    interpretarFunc2(fis);
                    break;
                case 4:
                    interpretarImp1(fis);
                    break;
                case 5:
                    interpretarImp2(fis);
                    break;
                case 6:
                    interpretarOO1(fis);
                    break;
            }
        } catch (Exception e1) {
            jTextAreaMensagens.setText(e1.getMessage());
            e1.printStackTrace();
        } catch (Throwable t) {
            jTextAreaMensagens.setText(t.getMessage());
        }

    }

    private void interpretarExp1(InputStream fis) throws ParseException {
        plp.expressions1.Programa prog;
        if (exp1Parser == null) {
            exp1Parser = new Exp1Parser(fis);
        } else {
            Exp1Parser.ReInit(fis);
        }
        prog = Exp1Parser.Input();
        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        if (prog.checaTipo()) {
            jTextAreaMensagens.append("resultado = "
                    + prog.executar().toString());
        } else {
            jTextAreaMensagens.append("erro de tipos!");
        }
    }

    private void interpretarExp2(InputStream fis) throws Exception {
        plp.expressions2.Programa prog;
        if (exp2Parser == null) {
            exp2Parser = new Exp2Parser(fis);
        } else {
            Exp2Parser.ReInit(fis);
        }
        prog = Exp2Parser.Input();

        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        if (prog.checaTipo()) {
            jTextAreaMensagens.append("resultado = "
                    + prog.executar().toString());
        } else {
            jTextAreaMensagens.append("erro de tipos!");
        }
    }

    private void interpretarFunc1(InputStream fis) throws Exception {
        plp.functional1.Programa prog;
        if (func1Parser == null) {
            func1Parser = new Func1Parser(fis);
        } else {
            Func1Parser.ReInit(fis);
        }
        prog = Func1Parser.Input();

        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        if (prog.checaTipo()) {
            jTextAreaMensagens.append("resultado = "
                    + prog.executar().toString());
        } else {
            jTextAreaMensagens.append("erro de tipos!");
        }
    }

    private void interpretarFunc2(InputStream fis) throws Exception {
        plp.functional2.Programa prog;
        if (func2Parser == null) {
            func2Parser = new Func2Parser(fis);
        } else {
            Func2Parser.ReInit(fis);
        }

        prog = Func2Parser.Input();

        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        jTextAreaMensagens.append("resultado = " + prog.executar().toString());
    }

    private void interpretarImp1(InputStream fis) throws Exception {
        plp.imperative1.Programa prog;
        if (imp1Parser == null) {
            imp1Parser = new Imp1Parser(fis);
        } else {
            Imp1Parser.ReInit(fis);
        }
        prog = Imp1Parser.Input();

        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        ListaValor entrada = obterListaEntrada(this.jTextFieldListaEntrada
                .getText());
        if (prog.checaTipo(new ContextoCompilacaoImperativa(entrada))) {
            JTextAreaOutputStream os = new JTextAreaOutputStream(jTextAreaMensagens);
            ContextoExecucaoImperativa contexto = new ContextoExecucaoImperativa(entrada, new PrintStream(os));
            prog.executar(contexto);
        } else {
            jTextAreaMensagens.append("erro de tipos!");
        }
    }

    private void interpretarImp2(InputStream fis) throws Exception {
        plp.imperative2.Programa prog;
        if (imp2Parser == null) {
            imp2Parser = new Imp2Parser(fis);
        } else {
            Imp2Parser.ReInit(fis);
        }

        prog = Imp2Parser.Input();

        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        ListaValor entrada = obterListaEntrada(this.jTextFieldListaEntrada
                .getText());
        if (prog.checaTipo(new ContextoCompilacaoImperativa2(entrada))) {
            JTextAreaOutputStream os = new JTextAreaOutputStream(jTextAreaMensagens);
            ContextoExecucaoImperativa2 contexto = new ContextoExecucaoImperativa2(entrada, new PrintStream(os));
            prog.executar(contexto);
        } else {
            jTextAreaMensagens.append("erro de tipos!");
        }
    }

    private void interpretarOO1(InputStream fis) throws Exception {
        plp.orientadaObjetos1.Programa prog;
        if (oo1Parser == null) {
            this.oo1Parser = new OO1Parser(fis);
        } else {
            oo1Parser.ReInit(fis);
        }
        prog = oo1Parser.processaEntrada();

        jTextAreaMensagens.setText("sintaxe verificada com sucesso!\n");
        plp.orientadaObjetos1.memoria.colecao.ListaValor entrada = obterListaEntrada2(this.jTextFieldListaEntrada
                .getText());
        if (prog
                .checaTipo(new plp.orientadaObjetos1.memoria.ContextoCompilacaoOO1(entrada))) {
            jTextAreaMensagens.append("resultado = "
                    + prog.executar(new plp.orientadaObjetos1.memoria.ContextoExecucaoOO1(entrada)).toString());
        } else {
            jTextAreaMensagens.append("erro de tipos!");
        }
    }

    private plp.orientadaObjetos1.memoria.colecao.ListaValor obterListaEntrada2(String texto) {
        List valores = new LinkedList();
        plp.orientadaObjetos1.memoria.colecao.ListaValor entrada = new plp.orientadaObjetos1.memoria.colecao.ListaValor();
        StringTokenizer parser = new StringTokenizer(texto);

        while (parser.hasMoreTokens()) {
            String parametro = parser.nextToken();

            try {
                Integer inteiro = Integer.valueOf(parametro);
                valores.add(new plp.orientadaObjetos1.expressao.valor.ValorInteiro(inteiro.intValue()));
                continue;
            } catch (NumberFormatException e) {

            }

            if (parametro.equalsIgnoreCase("true")
                    || parametro.equalsIgnoreCase("false")) {
                Boolean booleano = Boolean.valueOf(parametro);
                valores.add(new plp.orientadaObjetos1.expressao.valor.ValorBooleano(booleano.booleanValue()));
            } else {
                valores.add(new plp.orientadaObjetos1.expressao.valor.ValorString(parametro));
            }
        }
        entrada = OO1Parser.criaListaValor(valores);
        return entrada;
    }

    private ListaValor obterListaEntrada(String texto) {
        List valores = new LinkedList();
        ListaValor entrada = new ListaValor();
        StringTokenizer parser = new StringTokenizer(texto);

        while (parser.hasMoreTokens()) {
            String parametro = parser.nextToken();

            try {
                Integer inteiro = Integer.valueOf(parametro);
                valores.add(new ValorInteiro(inteiro.intValue()));
                continue;
            } catch (NumberFormatException e) {

            }

            if (parametro.equalsIgnoreCase("true")
                    || parametro.equalsIgnoreCase("false")) {
                Boolean booleano = Boolean.valueOf(parametro);
                valores.add(new ValorBooleano(booleano.booleanValue()));
            } else {
                valores.add(new ValorString(parametro));
            }
        }
        entrada = Imp1Parser.criaListaValor(valores);
        return entrada;
    }

    @Override
    public void start() {
        super.start();
        this.setVisible(true);
    }

    @Override
    public void init() {
        // TODO Auto-generated method stub
        super.init();
        this.initialize();
    }
} // @jve:decl-index=0:visual-constraint="10,10"

class AppletInterpretadorKeyListener implements KeyListener {

    AppletInterpretadorPLP applet;

    public AppletInterpretadorKeyListener(AppletInterpretadorPLP applet) {
        super();
        this.applet = applet;
    }

    public void keyPressed(java.awt.event.KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_F1) {
            this.applet.interpretarCodigo();
        }
    }

    public void keyReleased(KeyEvent arg0) {
    }

    public void keyTyped(KeyEvent arg0) {
    }
}
